package xyz.wadewhy.basicstest.easyExcel.color

import com.alibaba.excel.enums.CellDataTypeEnum
import com.alibaba.excel.metadata.Head
import com.alibaba.excel.metadata.data.WriteCellData
import com.alibaba.excel.util.MapUtils
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy
import org.apache.poi.ss.usermodel.Cell
import kotlin.math.min

/**
 * 自适应行宽
 */
class CellRowWightStyleStrategy : AbstractColumnWidthStyleStrategy() {

    private val cache: MutableMap<Int, MutableMap<Int, Int>> = MapUtils.newHashMapWithExpectedSize(8)

    private val MAX_COLUMN_WIDTH = 255

    private val Cell_ONE_LINE_MAX_CHAR = 100

    override fun setColumnWidth(
        writeSheetHolder: WriteSheetHolder, cellDataList: List<WriteCellData<*>?>, cell: Cell,
        head: Head?, relativeRowIndex: Int, isHead: Boolean
    ) {
        val needSetWidth = isHead || !org.apache.commons.collections4.CollectionUtils.isEmpty(cellDataList)
        if (!needSetWidth) {
            return
        }
        val maxColumnWidthMap = cache.computeIfAbsent(writeSheetHolder.sheetNo) { k: Int? -> HashMap(16) }
        var columnWidth = dataLength(cellDataList, cell, isHead)
        if (columnWidth < 0) {
            return
        }
        if (columnWidth > MAX_COLUMN_WIDTH) {
            columnWidth = MAX_COLUMN_WIDTH
        }
        val maxColumnWidth = maxColumnWidthMap[cell.columnIndex]
        if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
            maxColumnWidthMap[cell.columnIndex] = columnWidth
            if (cell.columnIndex == 1) {
                writeSheetHolder.sheet.setColumnWidth(cell.columnIndex, 100 * 100)
            } else {
                writeSheetHolder.sheet.setColumnWidth(cell.columnIndex, columnWidth * 150)
            }
        }
    }

    private fun dataLength(cellDataList: List<WriteCellData<*>?>, cell: Cell, isHead: Boolean): Int {
        if (isHead) {
            return cell.stringCellValue.toByteArray().size
        }
        val cellData = cellDataList[0]
        val type = cellData!!.type ?: return -1
        return when (type) {
            CellDataTypeEnum.STRING -> {
                min(cellData.stringValue.toByteArray().size, Cell_ONE_LINE_MAX_CHAR)
            }
            CellDataTypeEnum.BOOLEAN -> cellData.booleanValue.toString().toByteArray().size
            CellDataTypeEnum.NUMBER -> cellData.numberValue.toString().toByteArray().size
            else -> -1
        }
    }
}
